package com.dong.web.clazz;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.dong.web.annotation.Action;
import com.dong.web.annotation.Auto;
import com.dong.web.annotation.Bean;
import com.dong.web.annotation.Path;
import com.dong.web.annotation.Service;
import com.dong.web.clazz.bean.ABean;
import com.dong.web.clazz.bean.DBean;
import com.dong.web.clazz.bean.SBean;
import com.dong.web.util.ClassUtil;
import com.dong.web.whold.Variables;

public final class ClazzHandler {

	public static final LinkedHashMap<String, ABean> ACTION_BEAN = new LinkedHashMap<String, ABean>();
	public static final LinkedHashMap<String, DBean> DONG_BEAN = new LinkedHashMap<String, DBean>();
	public static final LinkedHashMap<String, SBean> SERVICE_BEAN = new LinkedHashMap<String, SBean>();
	private static final String FILE_END = ".class";

	public static void find() {
		find("");
	}

	public static void find(String scanning) {
		scanning = scanning == null ? "" : scanning;
		String[] paths = scanning.split(",");
		for (String path : paths) {
			int len = path.length();
			String left = "/";
			boolean isFile = false;
			if (path.length() > 0) {
				if (path.endsWith("..")) {
					left += path.substring(0, len - 1);
					left = left.replace(".", "/");
				} else {
					left += path.substring(0, path.lastIndexOf(".") + 1);
					left = left.replace(".", "/");
					isFile = true;
				}
			}
			String url = ClassUtil.getPath() + left;
			url = url.replace("\\", "/").replace("//", "/");
			if (isFile) {
				String javaName = path;
				analysisClass(javaName);
			} else {
				loopFile(url);
			}
		}
	}

	private static void loopFile(String url) {
		File file = new File(url);
		if (file.exists()) {
			if (file.isFile()) {
				getClassNameByUrl(file.getAbsolutePath());
			} else {
				File[] files = file.listFiles();
				for (File temp : files) {
					if (temp.isFile()) {
						getClassNameByUrl(temp.getAbsolutePath());
					} else {
						loopFile(temp.getAbsolutePath() + "/");
					}
				}
			}
		}
	}

	private static void getClassNameByUrl(String url) {
		url = url.replace("\\", "/").replace("//", "/");
		if (url.endsWith(FILE_END)) {
			String javaName = url.substring(url.lastIndexOf(Variables.WEB_INF)
					+ Variables.WEB_INF_LEN + 1);
			javaName = javaName.substring(0,
					javaName.length() - FILE_END.length()).replace("/", ".");
			analysisClass(javaName);
		}
	}

	private static void analysisClass(String javaName) {
		try {
			Class<?> clazz = Class.forName(javaName);
			if (clazz.isAnnotationPresent(Action.class)) {
				Action module = clazz.getAnnotation(Action.class);
				String value = module.value();
				if (!ACTION_BEAN.containsKey(value)) {
					boolean singleton = module.singleton();
					ABean bean = new ABean();
					bean.setClazz(clazz);
					bean.setMethods(clazz.getDeclaredMethods());
					Map<String, Method> actionMethods = new HashMap<String, Method>();
					for (Method method : bean.getMethods()) {
						if (method.isAnnotationPresent(Path.class)) {
							Path actionMethod = method
									.getAnnotation(Path.class);
							actionMethods.put(actionMethod.value(), method);
						}
					}
					bean.setActionMethods(actionMethods);
					bean.setSingleton(singleton);
					bean.setUrl(value);
					Field[] fields = clazz.getDeclaredFields();
					List<Field> fieldList = new ArrayList<Field>();
					for (Field field : fields) {
						if (field.isAnnotationPresent(Auto.class)) {
							fieldList.add(field);
						}
					}
					bean.setFields(fieldList);
					ACTION_BEAN.put(value, bean);
				}
			} else if (clazz.isAnnotationPresent(Bean.class)) {
				Bean bean = clazz.getAnnotation(Bean.class);
				String key = bean.value().length() == 0 ? clazz.getName()
						: bean.value();
				if (!DONG_BEAN.containsKey(key)) {
					DBean dbean = new DBean();
					dbean.setName(key);
					dbean.setClazz(clazz);
					dbean.setSingleton(bean.singleton());
					Field[] fields = clazz.getDeclaredFields();
					List<Field> fieldList = new ArrayList<Field>();
					for (Field field : fields) {
						if (field.isAnnotationPresent(Auto.class)) {
							fieldList.add(field);
						}
					}
					dbean.setFields(fieldList);
					DONG_BEAN.put(key, dbean);
				}
			} else if (clazz.isAnnotationPresent(Service.class)) {
				Service service = clazz.getAnnotation(Service.class);
				String key = (service.value().length() == 0 ? clazz.getName()
						: service.value()) + ",";
				Type[] types = clazz.getGenericInterfaces();
				List<String> interfaces = new ArrayList<String>();
				for (Type type : types) {
					String name = type.toString();
					name = name.substring(name.indexOf(" ") + 1);
					key += name + ",";
					interfaces.add(name);
				}
				if (!SERVICE_BEAN.containsKey(key)) {
					SBean sbean = new SBean();
					sbean.setName(key);
					sbean.setClazz(clazz);
					sbean.setSingleton(service.singleton());
					Field[] fields = clazz.getDeclaredFields();
					List<Field> fieldList = new ArrayList<Field>();
					for (Field field : fields) {
						if (field.isAnnotationPresent(Auto.class)) {
							fieldList.add(field);
						}
					}
					sbean.setFields(fieldList);
					sbean.setInterfaces(interfaces);
					SERVICE_BEAN.put(key, sbean);
				}
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static void delete(String module) {
		if (module.endsWith("/")) {
			Iterator<Map.Entry<String, ABean>> iterator = ACTION_BEAN
					.entrySet().iterator();
			while (iterator.hasNext()) {
				Map.Entry<String, ABean> entry = iterator.next();
				String key = entry.getKey();
				if (key.startsWith(module)) {
					iterator.remove();
				}
			}
		} else {
			if (ACTION_BEAN.containsKey(module)) {
				ACTION_BEAN.remove(module);
			}
		}
	}

}
